import entity.Customer;
import entity.Dish;
import entity.Order;
import entity.OrderDetail;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

import static biz.MeiTuan.*;

/**
 * Description：吃货联盟订餐系统（美团系统）服务端
 * Copyright (c), 2024, lbs
 * This program is protected by copyright laws.
 * Date： 2024年09月26日
 *
 * @author 刘宝顺
 * @version : 1.0
 **/

public class MeiTuanServer {
    /**
     * 系统无参数的构造方法
     */
    public MeiTuanServer() {
        //关于当前顾客的历史订单信息
        aboutCurrentSystemInfos(MEITUAN_FILE_NAME);
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        MeiTuanServer instance = new MeiTuanServer();

        List<String> names = Arrays.asList("张无忌", "赵敏", "周芷若", "张三丰", "韦一笑");

        AtomicInteger atomicInteger = new AtomicInteger(0);

        ExecutorService pool = Executors.newFixedThreadPool(5,
                r -> new Thread(r, names.get(atomicInteger.getAndIncrement() % names.size()))
        );


        try (ServerSocket server = new ServerSocket(7777)) {
            while (true) {
                System.out.println("准备为顾客提供点餐服务了哦...");
                Socket client = server.accept();
                System.out.println("顾客信息是：" + client);
                pool.submit(() -> instance.serviceForCustomer(client));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void aboutCurrentSystemInfos(String fileName) {
        //从磁盘上读取Order集合的实例到内存中
        File diskFile = new File("data/".concat(fileName).concat(".txt"));
        if (diskFile.exists()) {
            readInfosFromDiskFile(diskFile);
        } else {
            //初始化菜品信息
            Collections.addAll(DISH_INFOS, new Dish(1001, "红烧带鱼", 20.50, 100), new Dish(1002, "鱼香肉丝", 19.80, 103), new Dish(1003, "蚂蚁上树", 16.60, 99));
        }
    }

    private void serviceForCustomer(Socket client) {
        try (PrintWriter pw = new PrintWriter(client.getOutputStream(), true);
             Scanner scanner = new Scanner(client.getInputStream())) {
            //显示欢迎信息
            showWelcomeInfo(pw);

            //系统为顾客提供服务
            provideServiceForCustomer(pw, scanner);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (client != null) {
                try {
                    client.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 系统为顾客提供服务
     *
     * @param pw
     * @param scanner
     */
    private void provideServiceForCustomer(PrintWriter pw, Scanner scanner) {
        pw.println(System.lineSeparator().concat("顾客您好，服务员【" + Thread.currentThread().getName() + "】为您提供点餐服务！"));
        pw.println("PROVIDER_SERVICE_FOR_CUSTOMER");

        EXIT_FLG:
        while (true) {
            //③显示菜单信息
            showMenuInfos(pw);

            //④根据顾客的输入进行相应的操作
            pw.println("请选择：");
            pw.println("CHOICE");
            String choice = scanner.nextLine();

            switch (choice) {
                case "1": //a)1 ←显示菜品信息
                    lookAllDish(pw);
                    break;
                case "2": //b)2 ←我要订餐
                    order(pw, scanner);
                    break;
                case "3"://c)3 ←查看餐袋
                    listOrders(pw);
                    break;
                case "4"://d)4 ←签收订单
                    confirmOrder(pw, scanner);
                    break;
                case "5"://e)5 ←删除订单
                    removeOrder(pw, scanner);
                    break;
                case "6"://f)6 ←我要点赞
                    thumbsUp(pw, scanner);
                    break;
                case "7"://g)7 ←退出系统
                    String exitFlg = exitSystem(pw, scanner);
                    if ("Y".equalsIgnoreCase(exitFlg)) {
                        break EXIT_FLG;
                    }
                    break;
                default:
                    pw.println("您录入的是【" + choice + "】，不正确，请在1~7中选择！");
                    pw.println("ERROR_CHOICE");
            }
        }
    }


    /**
     * 显示欢迎信息
     */
    private void showWelcomeInfo(PrintWriter pw) {
        pw.println("欢迎使用“吃货联盟订餐系统”(附注：网络版修改后)");
        pw.println("WELCOME_INFO");
    }

    /**
     * 获得Scanner扫描器类的实例
     */
    private Scanner getScannerInstance() {
        Scanner input = new Scanner(System.in);
        return input;
    }

    /**
     * 显示所有的菜品信息
     *
     * @param pw
     */
    private void lookAllDish(PrintWriter pw) {
        showDishInfo(pw);
    }

    /**
     * 退出系统
     */
    private String exitSystem(PrintWriter pw, Scanner input) {
        pw.println("您确定退出点餐系统吗？（Y/N）：");
        pw.println("EXIT_SYSTEM");
        String flg = input.nextLine();
        if ("Y".equalsIgnoreCase(flg)) {
            pw.println("谢谢使用，欢迎下次光临！");
            pw.println("THANK_YOU_USING");
            //将内存中的订单信息保存到磁盘文件中
            File file = new File("data/".concat(MEITUAN_FILE_NAME).concat(".txt"));
            saveDishsAndOrdersToFile(file);

        }
        return flg;
    }

    /**
     * 我要点赞
     *
     * @param pw
     * @param input Scanner的实例
     */
    private void thumbsUp(PrintWriter pw, Scanner input) {
        pw.println("***我要点赞***");
        pw.println("THUMBS_UP");
        //思路：
        //①显示菜品信息  ← 遍历菜品的二维数组
        //显示菜品信息
        showDishInfo(pw);

        //②获得要点赞的菜品的序号
        pw.println(System.lineSeparator().concat("请录入要点赞的菜单序号："));
        pw.println("THUMBS_UP_NO");
        int foodNo = Integer.parseInt(input.nextLine());

        //③从所有菜品中定位到待点赞的菜品，将点赞数 + 1
        Dish willThumbUpDish = getDish(foodNo);
        willThumbUpDish.setThumbsUpCnt(willThumbUpDish.getThumbsUpCnt() + 1);

        pw.println(System.lineSeparator().concat("点赞操作成功了哦！☺☺☺"));
        pw.println("THUMBS_UP_SUCCESS");
    }


    /**
     * 删除订单
     *
     * @param pw
     * @param input
     */
    private void removeOrder(PrintWriter pw, Scanner input) {
        pw.println("***删除订单***");
        pw.println("REMOVE_ORDER");
        //①获得待删除的订单的编号
        String willRemoveNoStrs = getAllNormalOrderNos("已完成");
        pw.println(willRemoveNoStrs);
        pw.println("GET_ALL_REMOVE_ORDER_NO");
        if (!"".equals(willRemoveNoStrs)) {
            pw.println("请录入要删除的订单编号：");
            pw.println("REMOVE_ORDER_NO");
            int orderNo = Integer.parseInt(input.nextLine());

            //②根据得到的订单编号从容器（集合）中查询到具体的订单信息
            Order orderInfo = getCurrentOrderInfo(orderNo);

            //③↓ 逻辑删除 ↓
            orderInfo.setFlg(1);
            pw.println("恭喜！编号为【" + orderNo + "】的订单删除成功了哦！☺");
            pw.println("LOGIC_REMOVE_SUCCESS");
        }
    }

    /**
     * 签收订单
     *
     * @param pw
     * @param input Scanner的实例
     */
    private void confirmOrder(PrintWriter pw, Scanner input) {
        pw.println("***签收订单***");
        pw.println("CONFIRM_ORDER");
        //①获得要签收的订单编号
        String willSignOrders = getAllNormalOrderNos("已预定");
        pw.println(willSignOrders);
        pw.println("ALL_NORMAL_ORDER_NOS");
        if (!"".equals(willSignOrders)) {
            pw.println("请录入要签收的订单编号：");
            pw.println("CONFIRM_ORDER_NO");
            int orderNo = Integer.parseInt(input.nextLine());

            //②根据订单编号获得订单的全部信息
            Order orderInfo = getCurrentOrderInfo(orderNo);
            orderInfo.setStatus("已完成");
            pw.println("恭喜！订单签收成功了哦！☺☺☺");
            pw.println("CONFIRM_ORDER_OVER");
        }
    }

    /**
     * 获得所有合法的订单编号
     *
     * @return 合法的订单编号
     */
    private String getAllNormalOrderNos(String status) {
        StringBuilder builder = new StringBuilder("");
        for (Order order : ORDER_INFOS) {
            if (order.getFlg() == 0 && order.getStatus().equals(status)) {
                builder.append(order.getNo())
                        .append(",");
            }
        }
        if (builder.length() > 0) {
            builder.deleteCharAt(builder.length() - 1);
        }
        return builder.toString();
    }

    /**
     * 根据订单编号返回订单的信息
     *
     * @param orderNo 订单编号
     * @return 订单的信息 （Order的实例）
     */
    private Order getCurrentOrderInfo(int orderNo) {
        for (Order currentOrderInfo : ORDER_INFOS) {
            if (orderNo == currentOrderInfo.getNo()) {
                return currentOrderInfo;
            }
        }
        return null;
    }

    /**
     * 查看餐袋
     *
     * @param pw
     */
    private void listOrders(PrintWriter pw) {
        pw.println("***查看餐袋***");
        //打印表头
        pw.println("序号\t\t订餐人\t\t餐品信息\t\t送餐时间\t\t送餐地址\t\t总金额\t\t订单状态");
        pw.println("————————————————————————————————————————————————————————————————————");

        //遍历集合，输出所有的订单信息
        for (Order orderInfo : ORDER_INFOS) {
            if (orderInfo != null && orderInfo.getFlg() == 0) {
                String orderStr = orderInfo.toString();
                int index = orderStr.lastIndexOf("\t\t");
                pw.println(orderStr.substring(0, index));
            }
        }

        pw.println("LIST_ORDERS");
    }

    /**
     * 我要点餐
     *
     * @param pw      Scanner的实例
     * @param scanner
     */
    private void order(PrintWriter pw, Scanner scanner) {
        pw.println("***我要订餐***");
        pw.println("WILL_ORDER");

        //直接判断
        int orderSize = getNormalOrderSize();
        pw.println(orderSize);
        pw.println("NOW_ORDER_SIZE");
        if (orderSize == MAX_ORDER_NUMBER) {
            pw.println("顾客您好！目前本餐厅顾客已满，下次为您服务！这儿有优惠券！☺☺☺");
            pw.println("MAX_ORDER_NUMBER");
            return;
        }

        //显示菜品信息
        showDishInfo(pw);
        //接收顾客的信息
        getCustomerInfo(pw, scanner);
    }


    /**
     * 接收顾客的信息
     *
     * @param pw
     */
    private void getCustomerInfo(PrintWriter pw, Scanner scanner) {
        //前提：
        //一个顾客下一个订单，一个订单包含一个订单明细 ←为了简化业务，如是来约定
        //准备四个实例（分别是：顾客，订单，订单明细）
        Customer customer = new Customer();
        Order order = new Order();
        OrderDetail detail = new OrderDetail();

        //建立上述实例之间的关联关系
        //Customer（1）←  Order（*）
        order.setCustomer(customer);

        //Oder（1） ←  OrderDetail（*）
        detail.setOrder(order);

        //Oder（1） →  OrderDetail（*）
        List<OrderDetail> details = order.getDetails();
        details.add(detail);
        order.setDetails(details);

        //将下述的信息封装到上述三个实例中
        pw.println("请问您的姓名：");
        pw.println("NAME");
        String name = scanner.nextLine();
        customer.setName(name);

        //获得合法的菜单序号
        pw.println("请问您想下单的菜品编号：");
        pw.println("DISH_NO");
        String dishNo = scanner.nextLine();
        int no = Integer.parseInt(dishNo);

        Dish dish = getDish(no);
        detail.setDish(dish);
        pw.println("请问您想下单的菜品【" + dish.getName() + "】的份数：");
        pw.println("DISH_NUMBERS");
        int cnt = Integer.parseInt(scanner.nextLine());
        detail.setCnt(cnt);

        //隐藏着一个需求：要计算订单金额
        double price = dish.getPrice();
        double orderPrice = cnt * price;
        //结合业务修改金额：
        //规则：订单金额≥50，免费送餐；否则，需要交6元送餐费
        int deliveryFee = orderPrice >= 50 ? 0 : 6;
        orderPrice += deliveryFee;
        order.setTotalPrice(orderPrice);

        //获得合法的送餐时间
        String time = getIegalTime(pw, scanner);
        order.setTime(time);

        pw.println("请问您的地址是哪儿：");
        pw.println("ADDRESS");
        String address = scanner.nextLine();
        customer.setAddress(address);

        //将上述获悉的信息添加到容器“订单信息”中
        order.setStatus("已预定");

        //设置最新的订单编号
        int newOrderNo = 0;
        if (ORDER_INFOS.size() == 0) {
            newOrderNo = 1;
        } else {
            //a)排序
            Collections.sort(ORDER_INFOS);
            //b)获取最大订单编号，+1
            newOrderNo = ORDER_INFOS.get(0).getNo() + 1;
        }

        //c)设置编号到新的订单实例中
        order.setNo(newOrderNo);

        //将订单添加到容器中
        add2OrderContainer(order);

        //显示订单信息：
        showOrderInfo(pw, order);
    }


    /**
     * 获得合法的送餐时间
     *
     * @param input Scanner的实例
     * @return 合法的送餐时间
     */
    private String getIegalTime(PrintWriter pw, Scanner input) {
        pw.println("请问什么时候给您送餐方便一些呢（本店的规定是10:00~20:00整点送餐）：");
        pw.println("TIME");
        String time = input.nextLine();
        int tmpTime = Integer.parseInt(time);
        return String.valueOf(tmpTime);
    }

    /**
     * 显示订单信息
     *
     * @param order 订单信息
     */
    private void showOrderInfo(PrintWriter pw, Order order) {
        pw.println("————————————————————————————————");
        pw.println("您好，订单信息如下，您核对一下☺");
        Customer customer = order.getCustomer();
        pw.println("顾客姓名：" + customer.getName());
        OrderDetail detail = order.getDetails().get(0);
        pw.println("菜品名：" + detail.getDish().getName());
        pw.println("份数：" + detail.getCnt()+"份");
        pw.println("送餐时间：" + order.getTime()+"点");
        pw.println("送餐地址：" + customer.getAddress());
        pw.println("金额（元）：" + String.format("%.2f", order.getTotalPrice())+"元");
        pw.println("ORDER_INFOS");
    }

    /**
     * 将订单信息添加到容器中
     *
     * @param order 订单实例
     */
    private void add2OrderContainer(Order order) {
        //向集合中添加一个元素
        ORDER_INFOS.add(order);
    }

    /**
     * 显示菜品信息
     */
    private void showDishInfo(PrintWriter pw) {
        pw.println("本餐厅有下述美味可口的菜肴可供选择：");
        pw.println("菜单序号\t\t名称\t\t单价\t\t点赞数");
        pw.println("————————————————————————————————————————");
        for (Dish perDish : DISH_INFOS) {
            pw.println(perDish);
        }
        pw.println("END_OF_DISH");
    }

    /**
     * 根据菜单序号返回当前菜品的信息
     *
     * @param flg 菜单序号
     * @return 菜品信息 （本质，就是菜品的实例）
     */
    private Dish getDish(double flg) {
        for (Dish dish : DISH_INFOS) {
            if (flg == dish.getNo()) {
                return dish;
            }
        }
        return null;
    }

    /**
     * 显示菜单信息
     */
    private void showMenuInfos(PrintWriter pw) {
        pw.println(System.lineSeparator().concat("**********************************************"));
        pw.println("1、查看菜单");
        pw.println("2、我要订餐");
        pw.println("3、查看餐袋");
        pw.println("4、签收订单");
        pw.println("5、删除订单");
        pw.println("6、我要点赞");
        pw.println("7、退出系统");
        pw.println("**********************************************");
        pw.println("END_OF_MENU");
    }
}
